package com.newboy.alipay.controller;


import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.newboy.alipay.config.AlipayConfig;
import com.newboy.alipay.entity.Alipay;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RestController
@RequestMapping("/api/ali")
@Slf4j
public class AliPayController {

    @Autowired
    private AlipayClient alipayClient; //支付宝提供的客户端

    @Autowired
    private AlipayConfig alipayConfig;  //使用自定义配置类

    // 测试地址：http://localhost:8080/api/ali/pay?orderId=2023122122111222&price=1&subject=iPhone
    @GetMapping("/pay")
    public void payOrder(Alipay alipay, HttpServletResponse response) throws IOException {
        // 1.准备支付的参数，包括需要支付的订单的id，价格，物品名称，
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(alipay.getOrderId()); // 需要支付的订单id，自定义的订单id，不能重复，唯一，已经支付的无法继续支付
        model.setTotalAmount(alipay.getPrice()); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject(alipay.getSubject()); // 要支付的物品，比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");  //销售产品码，电脑支付场景就使用FAST_INSTANT_TRADE_PAY

        // 2.创建支付的请求，设置上面的准备支付的参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);

        // 3.设置支付宝异步回调，这个需要用内网穿透
        request.setNotifyUrl(alipayConfig.getNotifyUrl());

        // 4.设置支付宝支付成功返回的页面，这里让支付成功直接回到static下的一个静态页面中
        request.setReturnUrl(alipayConfig.getReturnUrl());

        // 5.调用ali客户端alipayClient，用客户端执行请求，获取响应，获取.getBody()，拿到form表单
        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
            System.out.println(form);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        // 6.表单数据作为响应返回给前端，显示前端页面
        response.setContentType("text/html;charset=UTF-8"); // 设置头部
        response.getWriter().write(form);// 直接将完整的表单html输出到页面
        response.getWriter().flush();
        response.getWriter().close();
    }

    /**
     * 支付宝异步回调
     * request.setNotifyUrl("");
     * http://localhost:8080/api/ali/notify
     * 上面这个网址用内网穿透代理一下
     * http://s8i6vq.natappfree.cc/api/ali/notify
     * 此时支付宝就能回调到这个页面
     */
    @PostMapping("/notify")
    public void aliPayNotify(HttpServletRequest request) throws AlipayApiException {
        log.debug(">>>>>>>支付宝异步回调");
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keySet = parameterMap.keySet(); // 获取http请求里面的所有键
        //重新创建一个Map再封装一次数据
        Map<String, String> paramsMap = new HashMap<>(); // 专门用来放置请求里面的参数
        for (String key : keySet) {
            paramsMap.put(key, request.getParameter(key));
        }
        System.out.println("*************");
        System.out.println(paramsMap);

        // 验证签名
        String sign = paramsMap.get("sign");
        String contentV1 = AlipaySignature.getSignCheckContentV1(paramsMap);
        boolean rsa256CheckSignature = AlipaySignature.rsa256CheckContent(contentV1, sign, alipayConfig.getAlipayPublicKey(), "UTF-8");
        if (rsa256CheckSignature && "TRADE_SUCCESS".equals(paramsMap.get("trade_status"))) {
            // 签名验证成功 并且 支付宝回调的状态是成功状态 TRADE_SUCCESS
            log.info("在{}，买家{}进行订单{}的付款，交易名称{}，付款金额{}",
                    paramsMap.get("gmt_payment"), paramsMap.get("buyer_id"), paramsMap.get("out_trade_no"), paramsMap.get("subject"), paramsMap.get("total_amount"));
            // 支付成功，修改数据库中该订单的状态
            // 比如：流程，根据订单ID查询出一条数据，修改该条订单的数据
            // 扣库存 + 订单状态修改
        } else {
            System.out.println("支付失败");
        }
    }

}
